using System;
using System.IO;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using GameFramework;
using UnityGameFramework.Runtime;

namespace LS.Saving
{
    /// <summary>
    /// 记录存档信息和存档数据的存档类
    /// </summary>
    public sealed class Database
    {
        private readonly Dictionary<string, object> m_Datas = new Dictionary<string, object>();
        private bool m_ValueChangedDirty = false;
        
        /// <summary>
        /// 获取游戏配置项数量。
        /// </summary>
        public int Count
        {
            get
            {
                return m_Datas.Count;
            }
        }

        public bool IsAnyChanged
        {
            get
            {
                return m_ValueChangedDirty;
            }
        }

        /// <summary>
        /// 获取所有游戏配置项的名称。
        /// </summary>
        /// <returns>所有游戏配置项的名称。</returns>
        public string[] GetAllNames()
        {
            return m_Datas.Keys.ToArray();
        }

        /// <summary>
        /// 获取所有游戏配置项的名称。
        /// </summary>
        /// <param name="results">所有游戏配置项的名称。</param>
        public void GetAllNames(List<string> results)
        {
            results.Clear();
            results.AddRange(m_Datas.Keys);
        }

        /// <summary>
        /// 检查是否存在指定游戏配置项。
        /// </summary>
        /// <param name="name">要检查游戏配置项的名称。</param>
        /// <returns>指定的游戏配置项是否存在。</returns>
        public bool HasData(string name)
        {
            return m_Datas.ContainsKey(name);
        }

        /// <summary>
        /// 移除指定游戏配置项。
        /// </summary>
        /// <param name="savingName">要移除游戏配置项的名称。</param>
        /// <returns>是否移除指定游戏配置项成功。</returns>
        public bool RemoveData(string savingName)
        {
            if (m_Datas.ContainsKey(savingName))
            {
                ChangedDirty();
            }

            return m_Datas.Remove(savingName);
        }

        /// <summary>
        /// 清空所有游戏配置项。
        /// </summary>
        public void RemoveAllSavings()
        {
            ChangedDirty();
            m_Datas.Clear();
        }

        /// <summary>
        /// 从指定游戏配置项中读取布尔值。
        /// </summary>
        /// <param name="savingName">要获取游戏配置项的名称。</param>
        /// <returns>读取的布尔值。</returns>
        public bool GetBool(string savingName)
        {
            object value = null;
            if (!m_Datas.TryGetValue(savingName, out value))
            {
                Log.Warning("Setting '{0}' is not exist.", savingName);
                return false;
            }

            return (bool)value;
        }

        /// <summary>
        /// 从指定游戏配置项中读取布尔值。
        /// </summary>
        /// <param name="savingName">要获取游戏配置项的名称。</param>
        /// <param name="defaultValue">当指定的游戏配置项不存在时，返回此默认值。</param>
        /// <returns>读取的布尔值。</returns>
        public bool GetBool(string savingName, bool defaultValue)
        {
            object value = null;
            if (!m_Datas.TryGetValue(savingName, out value))
            {
                return defaultValue;
            }
            return (bool)value;
        }

        /// <summary>
        /// 向指定游戏配置项写入布尔值。
        /// </summary>
        /// <param name="savingName">要写入游戏配置项的名称。</param>
        /// <param name="value">要写入的布尔值。</param>
        public void SetBool(string savingName, bool value)
        {
            object valueObj = value;
            bool result = m_Datas.TryGetValue(savingName, out object dataValue);
            if ((result && dataValue != valueObj) || !result)
            {
                ChangedDirty();
                m_Datas[savingName] = valueObj;
            }
        }

        /// <summary>
        /// 从指定游戏配置项中读取整数值。
        /// </summary>
        /// <param name="savingName">要获取游戏配置项的名称。</param>
        /// <returns>读取的整数值。</returns>
        public int GetInt(string savingName)
        {
            if (!m_Datas.TryGetValue(savingName, out object value))
            {
                Log.Warning("Setting '{0}' is not exist.", savingName);
                return 0;
            }

            return (int)value;
        }

        /// <summary>
        /// 从指定游戏配置项中读取整数值。
        /// </summary>
        /// <param name="savingName">要获取游戏配置项的名称。</param>
        /// <param name="defaultValue">当指定的游戏配置项不存在时，返回此默认值。</param>
        /// <returns>读取的整数值。</returns>
        public int GetInt(string savingName, int defaultValue)
        {
            if (!m_Datas.TryGetValue(savingName, out object value))
            {
                return defaultValue;
            }

            return (int)value;
        }

        /// <summary>
        /// 向指定游戏配置项写入整数值。
        /// </summary>
        /// <param name="savingName">要写入游戏配置项的名称。</param>
        /// <param name="value">要写入的整数值。</param>
        public void SetInt(string savingName, int value)
        {
            object valueObj = value;
            bool result = m_Datas.TryGetValue(savingName, out object dataValue);
            if ((result && dataValue != valueObj) || !result)
            {
                ChangedDirty();
                m_Datas[savingName] = valueObj;
            }
        }

        /// <summary>
        /// 从指定游戏配置项中读取浮点数值。
        /// </summary>
        /// <param name="savingName">要获取游戏配置项的名称。</param>
        /// <returns>读取的浮点数值。</returns>
        public float GetFloat(string savingName)
        {
            if (!m_Datas.TryGetValue(savingName, out object value))
            {
                Log.Warning("Setting '{0}' is not exist.", savingName);
                return 0;
            }

            return  (float)value;
        }

        /// <summary>
        /// 从指定游戏配置项中读取浮点数值。
        /// </summary>
        /// <param name="savingName">要获取游戏配置项的名称。</param>
        /// <param name="defaultValue">当指定的游戏配置项不存在时，返回此默认值。</param>
        /// <returns>读取的浮点数值。</returns>
        public float GetFloat(string savingName, float defaultValue)
        {
            if (!m_Datas.TryGetValue(savingName, out object value))
            {
                return defaultValue;
            }

            return (float)value;
        }

        /// <summary>
        /// 向指定游戏配置项写入浮点数值。
        /// </summary>
        /// <param name="savingName">要写入游戏配置项的名称。</param>
        /// <param name="value">要写入的浮点数值。</param>
        public void SetFloat(string savingName, float value)
        {
            object valueObj = value;
            bool result = m_Datas.TryGetValue(savingName, out var dataValue);
            if ((result && dataValue != valueObj) || !result)
            {
                ChangedDirty();
                m_Datas[savingName] = valueObj;
            }
        }

        /// <summary>
        /// 从指定游戏配置项中读取字符串值。
        /// </summary>
        /// <param name="savingName">要获取游戏配置项的名称。</param>
        /// <returns>读取的字符串值。</returns>
        public string GetString(string savingName)
        {
            if (!m_Datas.TryGetValue(savingName, out object value))
            {
                Log.Warning("Setting '{0}' is not exist.", savingName);
                return string.Empty;
            }

            return (string)value;
        }

        /// <summary>
        /// 从指定游戏配置项中读取字符串值。
        /// </summary>
        /// <param name="savingName">要获取游戏配置项的名称。</param>
        /// <param name="defaultValue">当指定的游戏配置项不存在时，返回此默认值。</param>
        /// <returns>读取的字符串值。</returns>
        public string GetString(string savingName, string defaultValue)
        {
            if (!m_Datas.TryGetValue(savingName, out object value))
            {
                return defaultValue;
            }

            return (string)value;
        }

        /// <summary>
        /// 向指定游戏配置项写入字符串值。
        /// </summary>
        /// <param name="savingName">要写入游戏配置项的名称。</param>
        /// <param name="value">要写入的字符串值。</param>
        public void SetString(string savingName, string value)
        {
            bool result = m_Datas.TryGetValue(savingName, out var dataValue);
            if ((result && dataValue != value) || !result)
            {
                ChangedDirty();
                m_Datas[savingName] = value;
            }
        }
        
        /// <summary>
        /// 从指定游戏配置项中读取数据。
        /// </summary>
        /// <param name="savingName">要获取游戏配置项的名称。</param>
        /// <returns>读取的字符串值。</returns>
        public T GetData<T>(string savingName)
        {
            if (!m_Datas.TryGetValue(savingName, out object value))
            {
                Log.Warning("Setting '{0}' is not exist.", savingName);
                return default(T);
            }

            return (T)value;
        }

        /// <summary>
        /// 从指定游戏配置项中读取数据。
        /// </summary>
        /// <param name="savingName">要获取游戏配置项的名称。</param>
        /// <param name="defaultValue">当指定的游戏配置项不存在时，返回此默认值。</param>
        /// <returns>读取的字符串值。</returns>
        public T GetData<T>(string savingName, T defaultValue)
        {
            if (!m_Datas.TryGetValue(savingName, out object value))
            {
                return defaultValue;
            }

            return (T)value;
        }

        /// <summary>
        /// 向指定游戏配置项写入数据。
        /// </summary>
        /// <param name="savingName">要写入游戏配置项的名称。</param>
        /// <param name="value">要写入的字符串值。</param>
        public void SetData<T>(string savingName, T value)
        {
            object inputValue = value;
            bool result = m_Datas.TryGetValue(savingName, out object dataValue);
            if ((result && dataValue != inputValue) || !result)
            {
                ChangedDirty();
                m_Datas[savingName] = inputValue;
            }
        }
        
        /// <summary>
        /// 从指定游戏配置项中读取数据。
        /// </summary>
        /// <param name="savingName">要获取游戏配置项的名称。</param>
        /// <returns>读取的字符串值。</returns>
        public object GetObject(string savingName)
        {
            if (!m_Datas.TryGetValue(savingName, out object value))
            {
                Log.Warning("Setting '{0}' is not exist.", savingName);
                return default;
            }

            return value;
        }

        /// <summary>
        /// 从指定游戏配置项中读取数据。
        /// </summary>
        /// <param name="savingName">要获取游戏配置项的名称。</param>
        /// <param name="defaultValue">当指定的游戏配置项不存在时，返回此默认值。</param>
        /// <returns>读取的字符串值。</returns>
        public object GetObject(string savingName, object defaultValue)
        {
            if (!m_Datas.TryGetValue(savingName, out object value))
            {
                return defaultValue;
            }

            return value;
        }

        /// <summary>
        /// 向指定游戏配置项写入数据。
        /// </summary>
        /// <param name="savingName">要写入游戏配置项的名称。</param>
        /// <param name="value">要写入的字符串值。</param>
        public void SetObject(string savingName, object value)
        {
            object inputValue = value;
            bool result = m_Datas.TryGetValue(savingName, out object dataValue);
            if ((result && dataValue != inputValue) || !result)
            {
                ChangedDirty();
                m_Datas[savingName] = inputValue;
            }
        }
        
        /// <summary>
        /// 清除所有数据
        /// </summary>
        public void Clear()
        {
            m_Datas.Clear();
            ChangedDirty();
        }

        public void ChangedDirty()
        {
            m_ValueChangedDirty = true;
        }

        public void ClearDirty()
        {
            m_ValueChangedDirty = false;
        }

        internal Dictionary<string, object> GetDataDictionary()
        {
            return m_Datas;
        }
    }
}
